library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;

entity MemoryArbiterCombinational is
  port
    (
      -- clk (neg-edge triggered), active-low reset
      clk, nReset     : in  std_logic;
      -- memory signals (in order)
      memAddr         : out std_logic_vector(15 downto 0);  -- mem address being read/written
      memWriteData    : out std_logic_vector(31 downto 0);  -- mem data to be written
      memWEN          : out std_logic;  -- write enable
      memREN          : out std_logic;  -- read enable
      memReadData     : in  std_logic_vector(31 downto 0);  -- mem data to be read
      memState        : in  std_logic_vector(1 downto 0);  -- state of mem
      -- icache signals (in order)
      icacheWait      : out std_logic;  -- icache must wait if 1
      icacheREN       : in  std_logic;  -- icache read request
      icacheAddr      : in  std_logic_vector(31 downto 0);  -- icache address being read
      icacheReadData  : out std_logic_vector(31 downto 0);  -- icache data to be read
      -- dcache signals (in order)
      dcacheREN       : in  std_logic;  -- dcache read request
      dcacheWEN       : in  std_logic;  -- dcache write request
      dcacheWait      : out std_logic;  -- dcache must wait if 1
      dcacheAddr      : in  std_logic_vector(31 downto 0);  -- dcache address being read
      dcacheReadData  : out std_logic_vector(31 downto 0);  -- dcache data to be read
      dcacheWriteData : in  std_logic_vector(31 downto 0)  -- dcache data to be written
      );
end MemoryArbiterCombinational;

architecture MemoryArbiterCombinational_arch of MemoryArbiterCombinational is

	signal t_memState : std_logic_vector(1 downto 0);
	
begin

	t_memState <= memState;

  process(icacheREN, dcacheREN, dcacheWEN, icacheAddr, dcacheAddr, dcacheWriteData, memReadData, t_memState)
  begin

    -- defaults
    icacheWait     <= '0';
    dcacheWait     <= '0';
    icacheReadData <= x"00000000";
    dcacheReadData <= x"00000000";
    memAddr        <= x"0000";
    memWriteData   <= x"00000000";
    memREN         <= '0';
    memWEN         <= '0';

    -- when inputs detected
    if(dcacheREN = '1' or dcacheWEN = '1') then
      icacheWait     <= '1';
      dcacheWait     <= '1';
      memREN         <= dcacheREN;
      memWEN         <= dcacheWEN;
      memAddr        <= dcacheAddr(15 downto 0);
      dcacheReadData <= memReadData;
      memWriteData   <= dcacheWriteData;
      if(t_memState = "01") then          -- accessing mem state
        dcacheWait <= '1';
        icacheWait <= '1';
      elsif(t_memState = "10") then  -- mem ready state
        dcacheWait <= '0';
        icacheWait <= '1';
      elsif(t_memState = "00") then  -- mem free state (won't last long b/c REN+WEN are connected)
        dcacheWait <= '1';
        icacheWait <= '1';
      else                              -- error state
        -- this likely means dcache REN and WEN are both 1
        dcacheWait <= '0';              -- set to zero b/c of inf loop hazard
        icacheWait <= '0';
      end if;
    elsif(icacheREN = '1') then
      dcacheWait     <= '1';
      icacheWait     <= '1';
      memREN         <= icacheRen;
      memWEN         <= '0';
      memAddr        <= icacheAddr(15 downto 0);
      icacheReadData <= memReadData;
      memWriteData   <= x"00000000";
      if(t_memState = "01") then          -- accessing mem state
        dcacheWait <= '1';
        icacheWait <= '1';
      elsif(t_memState = "10") then       -- mem ready state (zero access time)
        icacheWait <= '0';
        dcacheWait <= '1';
      elsif(t_memState = "00") then  -- mem free state (won't last long b/c REN is connected)
        icacheWait <= '1';
        dcacheWait <= '1';
      else                              -- error state (unlikely)
        icacheWait <= '0';              -- set to zero b/c of inf loop hazard
        dcacheWait <= '0';
      end if;
    end if;

  end process;
  
end MemoryArbiterCombinational_arch;
